package com.liao.badminton.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.liao.badminton.entity.SystemMenu;
import com.liao.badminton.entity.SystemRole;
import com.liao.badminton.redis.RedisUtil;
import com.liao.badminton.service.PermissionApi;
import com.liao.badminton.service.SystemRoleMenuService;
import com.liao.badminton.service.SystemRoleService;
import com.google.common.collect.Sets;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;

import static cn.hutool.core.util.ObjectUtil.isNotEmpty;
import static com.liao.badminton.code.util.CollectionUtils.convertSet;
import static com.liao.badminton.redis.RedisEnum.CACHE_TABLE_DATA;
import static com.liao.badminton.redis.RedisEnum.badminton_sys_menuid_roleids;

/**
 * 权限 API 实现类
 *
 * @author 芋道源码
 */
@Service
public class PermissionApiImpl implements PermissionApi {

    @Resource
    SystemRoleMenuService systemRoleMenuService;
    @Resource
    SystemMenuServiceImpl sysMenuService;
    @Resource
    SystemRoleService systemRoleService;

    @Override
    public boolean hasAnyPermissions(String userName, String... Menus) {
        // 如果为空，说明已经有权限
        if (ArrayUtil.isEmpty(Menus)) {
            return true;
        }

        // 获得当前登录的角色。如果为空，说明没有权限
        List<SystemRole> roles = systemRoleService.findByUserName(userName);
        if (CollUtil.isEmpty(roles)) {
            return false;
        }

        // 情况一：遍历判断每个权限，如果有一满足，说明有权限
        for (String Menu : Menus) {
            if (hasAnyPermissions(roles, Menu)) {
                return true;
            }
        }
        // 情况二：如果是超管，也说明有权限
        return systemRoleService.hasAnySuperAdmin(convertSet(roles, SystemRole::getId));
    }

    /**
     * 判断指定角色，是否拥有该 Menu 权限
     *
     * @param roles 指定角色数组
     * @param Menu  权限标识
     * @return 是否拥有
     */
    private boolean hasAnyPermissions(List<SystemRole> roles, String Menu) {
        List<SystemMenu> list = (List<SystemMenu>) RedisUtil.toGetDate(CACHE_TABLE_DATA, "systemMenu", "permission", Menu);
        if (list == null) {
            LambdaQueryWrapper<SystemMenu> objectQueryWrapper = new LambdaQueryWrapper<>();
            objectQueryWrapper.eq(SystemMenu::getPermission, Menu);
            list = sysMenuService.list(objectQueryWrapper);
            RedisUtil.toSaveRedis(CACHE_TABLE_DATA, "systemMenu", "permission", Menu, list, null);
        }
        // 采用严格模式，如果权限找不到对应的 Menu 的话，也认为没有权限
        if (CollUtil.isEmpty(list)) {
            return false;
        }

        // 判断是否有权限
        Set<Long> roleIds = convertSet(roles, SystemRole::getId);
        for (SystemMenu sysMenu : list) {
            Long id = sysMenu.getId();
            Set<Long> menuRoleIds = (Set<Long>) RedisUtil.toGetDate(badminton_sys_menuid_roleids, id);
            if (ObjectUtil.isEmpty(menuRoleIds)) {
                 menuRoleIds = systemRoleMenuService.findRoleIdsByMenuId(id);
                if (isNotEmpty(menuRoleIds)) {
                    RedisUtil.toSaveRedis(badminton_sys_menuid_roleids, id, menuRoleIds);
                }
            }
            // 获得拥有该菜单的角色编号集合
            // 如果有交集，说明有权限
            if (CollUtil.containsAny(menuRoleIds, roleIds)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean hasAnyRoles(String userName, String... roles) {
        // 如果为空，说明已经有权限
        if (ArrayUtil.isEmpty(roles)) {
            return true;
        }

        // 获得当前登录的角色。如果为空，说明没有权限
        List<SystemRole> rolesDB = systemRoleService.findByUserName(userName);
        if (CollUtil.isEmpty(rolesDB)) {
            return false;
        }

        // 判断是否有角色
        Set<String> userRoles = convertSet(rolesDB, SystemRole::getCode);
        return CollUtil.containsAny(userRoles, Sets.newHashSet(roles));
    }
}
